package com.binhthuan.catechist.client;

import java.util.LinkedHashMap;

import com.binhthuan.catechist.client.content.HomePage;
import com.binhthuan.catechist.client.menu.StackMenuItem;
import com.binhthuan.catechist.shared.constant.Action;
import com.binhthuan.catechist.shared.constant.ApplicationConstants;
import com.binhthuan.catechist.shared.constant.Operation;
import com.binhthuan.catechist.shared.constant.Parameter;
import com.binhthuan.catechist.shared.constant.Service;
import com.binhthuan.catechist.shared.session.UserSession;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
import com.smartgwt.client.core.KeyIdentifier;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.rpc.HandleErrorCallback;
import com.smartgwt.client.rpc.HandleTransportErrorCallback;
import com.smartgwt.client.rpc.RPCManager;
import com.smartgwt.client.types.DateDisplayFormat;
import com.smartgwt.client.types.TabBarControls;
import com.smartgwt.client.util.DateUtil;
import com.smartgwt.client.util.KeyCallback;
import com.smartgwt.client.util.Page;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.ImgButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
import com.smartgwt.client.widgets.tree.events.LeafClickEvent;
import com.smartgwt.client.widgets.tree.events.LeafClickHandler;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class ExemplaryCatechist implements EntryPoint, ValueChangeHandler<String> {

    private static final String LOADING_PANEL_ID = "loadingWrapper";
    private static final String LOGIN_PANEL_ID = "loginWrapper";
    private static final String LOGIN_ERROR_PANEL_ID = "errorWrapper";
    private static final String LOGINFORM_ID = "loginForm";
    private static final String LOGIN_ERROR_MESSAGE_ID = "errorMessage";
    private static final String USERNAME_ID = "username";
    private static final String PASSWORD_ID = "password";
    private static final String ECSERVICE = "ecservice";
    // private static final String REMEMBERME_ID = "rememberMe";

    /**
     * Các tham số được sử dụng trong chương trình.
     */
    private static ECConstants constants;

    /**
     * Các câu thông báo được sử dụng trong chương trình.
     */
    private static ECMessages messages;

    /**
     * Màn hình chức năng của chương trình.
     */
    private TabSet mainTabPanel;

    /**
     * Menu chuột phải khi nhấn vào tab.
     */
    private ContextMenu contextMenu;

    /**
     * Menu chính của chương trình.
     */
    private NavigationMenu sideNavMenu;

    /**
     * Layout chính của chương trình.
     */
    private VLayout mainLayout;

    /**
     * Trang chủ của chương trình.
     */
    private Tab homePage;

    /**
     * Cho biết màn hình đăng nhập đã được chuẩn bị hay chưa.
     */
    private boolean loginFormInitialized;
    String msg = new String();

    /**
     * This is the entry point method.
     */
    public void onModuleLoad() {
        System.out.println(Location.getHash());
        System.out.println(Location.getHost());
        System.out.println(Location.getHostName());
        System.out.println(Location.getHref());
        System.out.println(Location.getPath());
        System.out.println(Location.getPort());
        System.out.println(Location.getPort());
        System.out.println(Location.getProtocol());
        // add shortcut key to display SC's debug console.
        if (!GWT.isScript()) {
            KeyIdentifier debugKey = new KeyIdentifier();
            debugKey.setCtrlKey(true);
            debugKey.setKeyName("1");

            Page.registerKey(debugKey, new KeyCallback() {
                public void execute(String keyName) {
                    SC.showConsole();
                }
            });
        }
        msg = "URL base: " + GWT.getHostPageBaseURL() + "<br/>";
        initDatetimeFormat();
        initRPCManager();
        UserSession.READER = GWT.create(UserSession.UserSessionReader.class);
        ECApplication.setEntryPoint(this);
        loginFormInitialized = false;

        getUserInfoFromServer();
    }

    private void initDatetimeFormat() {
        DateUtil.setDefaultDisplayTimezone("00:00");
        DateUtil.setShortDateDisplayFormat(DateDisplayFormat.TOEUROPEANSHORTDATE);
        DateUtil.setNormalDateDisplayFormat(DateDisplayFormat.TOEUROPEANSHORTDATETIME);
    }

    private void initRPCManager() {
        RPCManager.setFetchDataPrompt(getMessages().loadingData());
        RPCManager.setSaveDataPrompt(getMessages().savingData());
        RPCManager.setRemoveDataPrompt(getMessages().removingData());
        RPCManager.setDefaultPrompt(getMessages().contactingToServer());
        RPCManager.setTimeoutErrorMessage(getMessages().operationTimeout());
        RPCManager.setHandleErrorCallback(new HandleErrorCallback() {

            @Override
            public void handleError(DSResponse response, DSRequest request) {
                GWT.log("handle Error callback: " + response.getStatus());
            }
        });

        RPCManager.setHandleTransportErrorCallback(new HandleTransportErrorCallback() {

            @Override
            public void handleTransportError(int transactionNum, int status, int httpResponseCode,
                    String httpResponseText) {
                GWT.log("handle Transport error callback");
                GWT.log("Status: " + status);
                GWT.log("HTTP response code: " + httpResponseCode);
                GWT.log("HTTP response: " + httpResponseText);
            }
        });
    }

    @SuppressWarnings("unused")
    private void getUserInfoFromServer() {
        String url = encodeURL(Service.AUTHENTICATION, Operation.FETCH, Action.GET_CURRENT_USER, null);
        msg = msg + "get user info: " + url + "<br/>";
        RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, URL.encode(url));
        try {
            Request request = builder.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request, Response response) {
                    msg = msg + "onResponseReceived: " + response.getText();
                    SC.say(msg);
                    UserSession userSession = UserSession.READER.read(response.getText());
                    // Ẩn màn hình loading
                    hideLoadingPanel();

                    if (userSession == null) {
                        GWT.log("No user info was found on server");
                        // Hiển thị màn hình đăng nhập
                        showLoginPage();
                    } else {
                        setUserInfo(userSession);
                        initComponents();
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    SC.say("onError");
                    GWT.log("Error while sending get user into request");
                    // Ẩn màn hình loading
                    hideLoadingPanel();
                    // Hiển thị màn hình đăng nhập
                    showLoginPage();
                }
            });
        } catch (RequestException e) {
            e.printStackTrace();
            GWT.log("Exception while sending get user into request");
            // Ẩn màn hình loading
            hideLoadingPanel();
            // Hiển thị màn hình đăng nhập
            showLoginPage();
        }
    }

    /**
     * Chuẩn bị màn hình đăng nhập.
     */
    private void initLoginForm() {
        if (loginFormInitialized) {
            GWT.log("Login form was initialized");
            return;
        }

        GWT.log("Initialize the login form");
        RootPanel.get("loginTitle").getElement().setInnerHTML(getConstants().memberLogin());
        RootPanel.get("usernameLabel").getElement().setInnerHTML(getConstants().username());
        RootPanel.get("passwordLabel").getElement().setInnerHTML(getConstants().password());
        RootPanel.get("login").getElement().setInnerHTML(getConstants().login());

        Anchor aboutLink = new Anchor(getConstants().about());
        aboutLink.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(com.google.gwt.event.dom.client.ClickEvent event) {
                Window aboutWindow = new Window();
                aboutWindow.setTitle(getConstants().about());
                aboutWindow.setShowMinimizeButton(false);
                aboutWindow.setIsModal(true);
                aboutWindow.setShowModalMask(true);
                aboutWindow.centerInPage();
                aboutWindow.addItem(new IButton(getConstants().about()));
                aboutWindow.show();
            }
        });
        RootPanel.get("about").add(aboutLink);

        LoginForm loginForm = new LoginForm(LOGINFORM_ID, USERNAME_ID, PASSWORD_ID);
        loginForm.addSubmitHandler(new SubmitHandler() {

            @Override
            public void onSubmit(SubmitEvent event) {
                if (event.getSource() instanceof LoginForm) {
                    LoginForm sourceForm = (LoginForm) event.getSource();
                    // Kiểm tra username và password có đầy đủ không.
                    String username = sourceForm.getUsername();
                    String password = sourceForm.getPassword();

                    if (username.trim().length() == 0) {
                        showLoginError(getMessages().missingUsername());
                        event.cancel();
                    } else if (password.trim().length() == 0) {
                        showLoginError(getMessages().missingPassword());
                        event.cancel();
                    } else if (!username.matches("\\w+")) {
                        showLoginError(getMessages().invalidUsername());
                        event.cancel();
                    } else {
                        GWT.log("Username and password are valid");
                        hideLoginError();
                        Document.get().getElementById("loadingMsg").setInnerHTML(getConstants().loading());

                        hideLoginPage();
                        showLoadingPanel();
                        login(username, password);
                    }
                } else {
                    event.cancel();
                }
            }
        });

        loginFormInitialized = true;
        GWT.log("Login form was initialized");
    }

    /**
     * Thành viên đăng nhập.
     * 
     * @param username
     *            Tên đăng nhập.
     * @param password
     *            Mật khẩu.
     */
    @SuppressWarnings("unused")
    protected void login(String username, String password) {
        StringBuffer parameter = new StringBuffer(Parameter.USERNAME);
        parameter.append("=").append(username).append("&").append(Parameter.PASSWORD).append("=").append(password);

        String url = encodeURL(Service.AUTHENTICATION, Operation.UPDATE, Action.LOGIN, parameter.toString());
        RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, URL.encode(url));
        try {
            GWT.log("Sent login request to server");
            Request request = builder.sendRequest(null, new RequestCallback() {
                @Override
                public void onResponseReceived(Request request, Response response) {
                    hideLoadingPanel();
                    if (response.getStatusCode() == Response.SC_OK) {
                        GWT.log("Login successfully");
                        // Đăng nhập thành công
                        UserSession userSession = UserSession.READER.read(response.getText());
                        setUserInfo(userSession);
                        showMainLayout();
                    } else if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
                        GWT.log("Login failed");
                        // Sai username và password
                        showLoginError(getMessages().usernameAndPasswordAreNotCorrect());
                        showLoginPage();
                        SC.say(response.getStatusText());
                    } else {
                        GWT.log("Got unhandled error from server");
                        // Gặp những lỗi khác
                        showLoginError(getMessages().errorFromServer());
                        showLoginPage();
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    GWT.log("Error while sending request");
                    hideLoadingPanel();
                    showLoginError(getMessages().cannotContactToServer());
                    showLoginPage();

                }
            });
        } catch (RequestException e) {
            GWT.log("Request exception has been caught");
            e.printStackTrace();
            hideLoadingPanel();
            showLoginError(getMessages().cannotContactToServer());
            showLoginPage();
        }
    }

    /**
     * Đăng xuất khỏi hệ thống.
     */
    @SuppressWarnings("unused")
    public void logout() {
        String url = encodeURL(Service.AUTHENTICATION, Operation.UPDATE, Action.LOGOUT, null);
        RequestBuilder buidler = new RequestBuilder(RequestBuilder.POST, URL.encode(url));
        try {
            Request request = buidler.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request, Response response) {
                    GWT.log("Sign out successfully");
                    setUserInfo(null);
                    hideMainLayout();
                    showLoginPage();
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    GWT.log("Error while sending sign out request");
                    setUserInfo(null);
                    hideMainLayout();
                    showLoginPage();
                }
            });
        } catch (RequestException e) {
            e.printStackTrace();
        }
    }

    /**
     * Hiển thị thông báo lỗi khi đăng nhập.
     * 
     * @param msg
     *            Thông điệp cần hiển thị.
     */
    protected void showLoginError(String msg) {
        Document.get().getElementById(LOGIN_ERROR_MESSAGE_ID).setInnerHTML(msg);
        Document.get().getElementById(LOGIN_ERROR_PANEL_ID).removeClassName("hide");
    }

    /**
     * Giấu thông báo lỗi khi đăng nhập.
     */
    protected void hideLoginError() {
        Document.get().getElementById(LOGIN_ERROR_PANEL_ID).addClassName("hide");
    }

    /**
     * Hiển thị màn hình loading.
     */
    public void showLoadingPanel() {
        RootPanel.get(LOADING_PANEL_ID).setVisible(true);
    }

    /**
     * Giấu màn hình loading.
     */
    public void hideLoadingPanel() {
        RootPanel.get(LOADING_PANEL_ID).setVisible(false);
    }

    /**
     * Hiển thị màn hình đăng nhập.
     */
    public void showLoginPage() {
        initLoginForm();
        RootPanel.get(LOGIN_PANEL_ID).setVisible(true);
    }

    /**
     * Giấu màn hình đăng nhập.
     */
    public void hideLoginPage() {
        RootPanel.get(LOGIN_PANEL_ID).setVisible(false);
    }

    /**
     * Khởi tạo module chính.
     */
    private void initComponents() {
        GWT.log("Initializing main module");
        final String initToken = History.getToken();
        // Layout chính của chương trình
        // if (mainLayout != null) {
        // mainLayout.destroy();
        // }
        mainLayout = new VLayout() {
            @Override
            protected void onDraw() {
                super.onDraw();
                if (initToken.length() != 0) {
                    GWT.log("FIRE THE CURRENT HISTORY STATE");
                    // Xử lý đường dẫn đầu tiên truy cập đến chương trình
                    onHistoryChanged(initToken);
                }
            }
        };
        mainLayout.setWidth100();
        mainLayout.setHeight100();

        // Thanh tiêu đề của chương trình
        ToolStrip topBar = createTopBar();
        mainLayout.addMember(topBar);

        // Layout chứa menu chính và màn hình chức năng
        HLayout hLayout = new HLayout();
        hLayout.setLayoutMargin(5);
        hLayout.setWidth100();
        hLayout.setHeight100();

        // Menu chính của chương trình
        hLayout.addMember(getNavigationMenu());

        // Màn hình chức năng của chương trình
        Canvas canvas = new Canvas();
        canvas.setWidth100();
        canvas.setHeight100();
        canvas.addChild(getMainTabPanel());

        hLayout.addMember(canvas);
        mainLayout.addMember(hLayout);
        mainLayout.draw();

        // Add history listener
        History.addValueChangeHandler(this);
        GWT.log("Main module has been initialized");
    }

    /**
     * 
     */
    private NavigationMenu getNavigationMenu() {
        if (sideNavMenu == null) {
            sideNavMenu = new NavigationMenu();
            sideNavMenu.setHeight100();
            sideNavMenu.setWidth(185);
            sideNavMenu.setShowResizeBar(true);
            sideNavMenu.setShowEdges(true);
            sideNavMenu.addLeafClickHandler(new LeafClickHandler() {

                @Override
                public void onLeafClick(LeafClickEvent event) {
                    StackMenuItem item = (StackMenuItem) event.getLeaf();
                    ContentFactory factory = item.getFactory();
                    if (factory == null) {
                        SC.warn("NOT FOUND");
                    } else if (!factory.checkCertificated(ECUser.getSecurityCode())) {
                        SC.warn("Do not have permision");
                    } else {
                        showContent(factory, factory.getIcon(), factory.getTitle());
                        History.newItem(item.getHistoryToken(), false);
                    }
                }
            });
        }

        return sideNavMenu;
    }

    /**
     * 
     */
    private TabSet getMainTabPanel() {
        if (mainTabPanel == null) {
            mainTabPanel = new TabSet();
            Layout paneContainerProperties = new Layout();
            paneContainerProperties.setLayoutMargin(0);
            paneContainerProperties.setLayoutTopMargin(1);
            mainTabPanel.setPaneContainerProperties(paneContainerProperties);
            mainTabPanel.setWidth100();
            mainTabPanel.setHeight100();

            // Hiển thị trang chủ
            mainTabPanel.addTab(getHomePage());
            mainTabPanel.addTabSelectedHandler(new TabSelectedHandler() {
                public void onTabSelected(TabSelectedEvent event) {
                    GWT.log("SELECT TAB: " + mainTabPanel.getSelectedTab().getID());
                    Tab selectedTab = event.getTab();
                    String historyToken = selectedTab.getAttribute(ApplicationConstants.HISTORY_TOKEN);
                    if (historyToken != null) {
                        History.newItem(historyToken, false);
                        getNavigationMenu().selectMenuItem(selectedTab.getID());
                    } else {
                        GWT.log("TOKEN IS NULL, GO TO HOME PAGE");
                        History.newItem(getHomePage().getAttribute(ApplicationConstants.HISTORY_TOKEN), false);
                    }
                }
            });
            // Tạo comboBox thay đổi ngôn ngữ
            LinkedHashMap<String, String> localeMap = new LinkedHashMap<String, String>();
            String currentLocale = LocaleInfo.getCurrentLocale().getLocaleName();
            if (currentLocale.equals(GwtLocale.DEFAULT_LOCALE)) {
                currentLocale = "en";
            }
            String[] localeNames = LocaleInfo.getAvailableLocaleNames();
            for (String localeName : localeNames) {
                if (!localeName.equals(GwtLocale.DEFAULT_LOCALE)) {
                    String nativeName = LocaleInfo.getLocaleNativeDisplayName(localeName);
                    localeMap.put(localeName, nativeName);
                }
            }

            LayoutSpacer layoutSpacer = new LayoutSpacer();
            layoutSpacer.setWidth(5);

            SelectItem selectItem = new SelectItem();
            selectItem.setHeight(21);
            selectItem.setWidth(130);
            selectItem.setValueMap(localeMap);

            selectItem.setDefaultValue(currentLocale);
            selectItem.setShowTitle(false);
            selectItem.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent event) {
                    String localeName = (String) event.getValue();
                    UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", localeName);
                    com.google.gwt.user.client.Window.Location.replace(builder.buildString());
                }
            });

            DynamicForm form = new DynamicForm();
            form.setPadding(0);
            form.setMargin(0);
            form.setCellPadding(1);
            form.setNumCols(1);
            form.setFields(selectItem);
            mainTabPanel.setTabBarControls(TabBarControls.TAB_SCROLLER, TabBarControls.TAB_PICKER, layoutSpacer, form);
        }

        return mainTabPanel;
    }

    /**
     * Tạo menu chuột phải cho tab
     * 
     * @return context menu
     */
    public ContextMenu getContextMenu() {
        if (contextMenu == null) {
            contextMenu = new ContextMenu(mainTabPanel, 0);
        }

        return contextMenu;
    }

    /**
     * @return
     */
    private ToolStrip createTopBar() {
        ToolStrip topBar = new ToolStrip();
        topBar.setHeight(33);
        topBar.setWidth100();

        topBar.addSpacer(6);
        ImgButton homeButton = new ImgButton();
        homeButton.setSrc("layout/logo.png");
        homeButton.setWidth(32);
        homeButton.setHeight(32);
        homeButton.setPrompt(getMessages().goToHomePage());
        homeButton.setHoverStyle("interactImageHover");
        homeButton.setShowRollOver(false);
        homeButton.setShowDownIcon(false);
        homeButton.setShowDown(false);
        homeButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
            public void onClick(ClickEvent event) {
                GWT.log(SC.getHome());
                History.newItem(getHomePage().getAttribute(ApplicationConstants.HISTORY_TOKEN), true);
            }
        });
        topBar.addMember(homeButton);
        topBar.addSpacer(6);

        Label title = new Label(ECApplication.getConstants().applicationName());
        title.setStyleName("title");
        title.setWidth(300);
        topBar.addMember(title);

        topBar.addFill();

        ToolStripButton aboutButton = new ToolStripButton();
        aboutButton.setTitle(getConstants().about());
        aboutButton.setIconSize(24);
        aboutButton.setIcon(ECIcons.getIcon24("author-info.png"));
        aboutButton.setPrompt(getMessages().aboutAuthor());
        aboutButton.setHoverStyle("interactImageHover");
        aboutButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
            public void onClick(ClickEvent event) {
                // Display about dialog
            }
        });

        topBar.addButton(aboutButton);

        ToolStripButton shutdownButton = new ToolStripButton();
        shutdownButton.setIconSize(24);
        shutdownButton.setIcon(ECIcons.getIcon24("shut-down.png"));
        shutdownButton.setPrompt(getMessages().signOut());
        shutdownButton.setHoverStyle("interactImageHover");
        shutdownButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
            public void onClick(ClickEvent event) {
                // Đăng xuất khỏi hệ thống
                logout();
            }
        });

        topBar.addButton(shutdownButton);

        topBar.addSpacer(6);
        return topBar;
    }

    /**
     * @return
     */
    private Tab getHomePage() {
        if (homePage == null) {
            homePage = new Tab();

            HomePage.Factory f = HomePage.Factory.getInstance();
            homePage.setTitle(f.getTitle());
            homePage.setIcon(f.getIcon());
            homePage.setPane(f.create());
            homePage.setID(f.getID());
            homePage.setAttribute(ApplicationConstants.HISTORY_TOKEN, f.getID());
        }
        return homePage;
    }

    private void showContent(ContentFactory factory, String icon, String title) {
        GWT.log("SHOW CONTENT: " + factory.getID());
        Tab contentTab = mainTabPanel.getTab(factory.getID());
        if (contentTab == null) {
            GWT.log("NOT FOUND TAB, ADD NEW TAB");
            contentTab = new Tab();
            if (icon == null) {
                icon = ApplicationConstants.DEFAULT_ICON;
            }
            String imgHTML = Canvas.imgHTML(icon, 16, 16);
            contentTab.setTitle("<span>" + imgHTML + "&nbsp;" + title + "</span>");
            contentTab.setContextMenu(getContextMenu());
            contentTab.setAttribute(ApplicationConstants.HISTORY_TOKEN, factory.getID());
            contentTab.setPane(factory.create());
            contentTab.setCanClose(true);
            contentTab.setID(factory.getID());
            mainTabPanel.addTab(contentTab);
            mainTabPanel.selectTab(contentTab);
        } else {
            mainTabPanel.selectTab(contentTab);
        }
    }

    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
        onHistoryChanged(event.getValue());
    }

    /**
     * Hàm xử lý khi người dùng nhập địa chỉ vào thanh address hay ấn Back,
     * Forward button.
     * 
     * @param historyToken
     */
    public void onHistoryChanged(String historyToken) {
        GWT.log("HISTORY CHANGED");
        ContentFactory factory = ECContents.getFactory(historyToken);
        if (factory == null) {
            SC.warn("NOT FOUND");
            History.back();
        } else if (!factory.checkCertificated(ECUser.getSecurityCode())) {
            SC.warn("Do not have permision");
            History.back();
        } else {
            showContent(factory, factory.getIcon(), factory.getTitle());
            getNavigationMenu().selectMenuItem(factory.getTitle());
        }
    }

    /**
     * Lấy các nhãn hiển thị trong chương trình.
     * 
     * @return
     */
    public static ECConstants getConstants() {
        if (constants == null) {
            constants = GWT.create(ECConstants.class);
        }

        return constants;
    }

    /**
     * Lấy các câu thông báo hiển thị trong chương trình.
     * 
     * @return
     */
    public static ECMessages getMessages() {
        if (messages == null) {
            messages = GWT.create(ECMessages.class);
        }

        return messages;
    }

    /**
     * Lấy thông tin người dùng.
     * 
     * @return Thông tin người dùng.
     */
    public UserSession getUserInfo() {
        return ECUser.getCurrentUser();
    }

    /**
     * Gán thông tin người dùng.
     * 
     * @param userInfo
     *            Thông tin người dùng.
     */
    public void setUserInfo(UserSession userInfo) {
        ECUser.setCurrentUser(userInfo);
    }

    /**
     * Ẩn màn hình chính.
     */
    public void hideMainLayout() {
        if (mainLayout.isDrawn()) {
            mainLayout.hide();
        }
    }

    /**
     * Hiện màn hình chính.
     */
    public void showMainLayout() {
        if (mainLayout != null && mainLayout.isDrawn() && mainLayout.isVisible()) {
            mainLayout.show();
        } else {
            initComponents();
        }
    }

    /**
     * Tạo đường dẫn tới server.
     * 
     * @return Đường dẫn tới server.
     */
    public String encodeURL() {
        /*StringBuffer buffer = new StringBuffer(EC_URL);
        buffer.append(ECSERVICE);

        return buffer.toString();
        */
        return createUrlBuilder().buildString();
    }

    /**
     * Tạo đường dẫn tới server.
     * 
     * @param serviceName
     *            Tên servlet
     * @return Đường dẫn tới server.
     */
    public String encodeURL(String serviceName) {
        /*
         * StringBuffer buffer = new StringBuffer(EC_URL);
         * buffer.append(ECSERVICE); buffer.append("?");
         * buffer.append(Parameter.SERVICE); buffer.append("=");
         * buffer.append(serviceName);
         * 
         * return buffer.toString();
         */
        return createUrlBuilder().setParameter(Parameter.SERVICE, serviceName).buildString();
    }

    /**
     * Tạo đường dẫn tới server.
     * 
     * @param serviceName
     *            Tên servlet
     * @param operation
     *            Tên hành động cần thực hiện.
     * @return Đường dẫn tới server.
     */
    public String encodeURL(String serviceName, String operation) {
        /*
         * StringBuffer buffer = new StringBuffer(EC_URL);
         * buffer.append(ECSERVICE); buffer.append("?");
         * buffer.append(Parameter.SERVICE); buffer.append("=");
         * buffer.append(serviceName); buffer.append("&");
         * buffer.append(Parameter.OPERATION); buffer.append("=");
         * buffer.append(operation);
         * 
         * return buffer.toString();
         */
        return createUrlBuilder().setParameter(Parameter.SERVICE, serviceName)
        .setParameter(Parameter.OPERATION, operation).buildString();
    }

    /**
     * Tạo đường dẫn tới server.
     * 
     * @param serviceName
     *            Tên service
     * @param operation
     *            Tên hành động cần thực hiện.
     * @param operationInfo
     * @return Đường dẫn tới server.
     */
    public String encodeURL(String serviceName, String operation, String operationInfo) {
        /*StringBuffer buffer = new StringBuffer(EC_URL);
        buffer.append(ECSERVICE);
        buffer.append("?");
        buffer.append(Parameter.SERVICE);
        buffer.append("=");
        buffer.append(serviceName);
        buffer.append("&");
        buffer.append(Parameter.OPERATION);
        buffer.append("=");
        buffer.append(operation);
        buffer.append("&");
        buffer.append(Parameter.OPERATION_INFO);
        buffer.append("=");
        buffer.append(operationInfo);

        return buffer.toString();
        */
        return createUrlBuilder().setParameter(Parameter.SERVICE, serviceName)
        .setParameter(Parameter.OPERATION, operation)
        .setParameter(Parameter.OPERATION_INFO, operationInfo).buildString();
    }

    /**
     * Tạo đường dẫn tới server.
     * 
     * @param serviceName
     *            Tên servlet
     * @param operation
     *            Tên hành động cần thực hiện.
     * @param operationInfo
     * @param parameterString
     *            Chuỗi tham số truyền tới server.
     * @return Đường dẫn tới server.
     */
    public String encodeURL(String serviceName, String operation, String operationInfo, String parameterString) {
        /*StringBuffer buffer = new StringBuffer(EC_URL);
        buffer.append(ECSERVICE);
        buffer.append("?");
        if (serviceName != null) {
            buffer.append(Parameter.SERVICE);
            buffer.append("=");
            buffer.append(serviceName);
        }
        if (operation != null) {
            buffer.append("&");
            buffer.append(Parameter.OPERATION);
            buffer.append("=");
            buffer.append(operation);
        }
        if (operationInfo != null) {
            buffer.append("&");
            buffer.append(Parameter.OPERATION_INFO);
            buffer.append("=");
            buffer.append(operationInfo);
        }
        if (parameterString != null && parameterString.trim().length() > 0) {
            buffer.append("&");
            buffer.append(parameterString);
        }

        return buffer.toString();
        */
        String url = null;
        UrlBuilder builder = createUrlBuilder();
        if (serviceName != null) {
            builder.setParameter(Parameter.SERVICE, serviceName);
        }
        if (operation != null) {
            builder.setParameter(Parameter.OPERATION, operation);
        }
        if (operationInfo != null) {
            builder.setParameter(Parameter.OPERATION_INFO, operationInfo);
        }

        url = builder.buildString();
        if (parameterString != null && parameterString.trim().length() > 0) {
            if(url.indexOf('?') == -1) {
                url = url.concat("?");
            }
            return url.concat("&").concat(parameterString);    
        }

        return url;
    }

    public UrlBuilder createUrlBuilder() {
        UrlBuilder builder = new UrlBuilder();
        builder.setProtocol(Location.getProtocol());
        builder.setHost(Location.getHost());
        builder.setPath(ECSERVICE);

        return builder;
    }
}
